#include "chattablemodel.h"
#include <QBrush>
#include <QPainter>
#include <QGraphicsPathItem>
#include <QLinearGradient>
#include <QGraphicsDropShadowEffect>
#include <QStyleOptionGraphicsItem>
#include <QTableView>
#include <QTextDocument>
#include <QAbstractTextDocumentLayout>

#include <iostream>

ChatItemDelegate::ChatItemDelegate(QObject * parent)
    :QStyledItemDelegate(parent),
    document(QSharedPointer<QTextDocument>(new QTextDocument)),
    contactProfileImage(NULL)
{

}

ChatItemDelegate::~ChatItemDelegate()
{

}

const int CORNER_RADIUS = 5;
const int ARROW_TOP = 5;
const int ARROW_WIDTH = 10;
const int ARROW_HEIGHT = 10;
const int PROFILE_AREA_WIDTH = 50;

#define TIMESTAMP_ROLE  (Qt::UserRole+2)
#define ARROW_ROLE      (Qt::UserRole+3)

 void ChatItemDelegate::bezierPathWithRect(QRect const& rect, QPainterPath& bp, bool leftArrow) const
 {
     float leftOX = rect.x();
     float leftX = leftOX;
     float rightX = leftOX + rect.width()-2 - ARROW_WIDTH;
         if (leftArrow) {
                 leftX = leftOX + ARROW_WIDTH;
                 rightX = leftOX + rect.width()-2;
         }
     float bottomY = rect.y();
     float topY = bottomY + rect.height()-2;

     QPoint startingPoint(leftX + ARROW_WIDTH, topY);
     bp.moveTo(startingPoint);
     QPoint cp(rightX, topY);
         // top right corner
     bp.lineTo(rightX-CORNER_RADIUS, topY);
     bp.quadTo(rightX, topY, rightX, topY - CORNER_RADIUS);

     if (!leftArrow) {
         bp.lineTo(rightX, topY-ARROW_TOP);
         bp.lineTo(rightX+ARROW_WIDTH, topY-ARROW_HEIGHT/2-ARROW_TOP);
         bp.lineTo(rightX, topY-ARROW_HEIGHT-ARROW_TOP);
     }

         // bottom right corner
         bp.lineTo(rightX, bottomY + CORNER_RADIUS);
         cp = QPoint(rightX, bottomY);
          bp.quadTo(rightX, bottomY,rightX - CORNER_RADIUS, bottomY);
         // bottom left corner
         bp.lineTo(leftX + CORNER_RADIUS, bottomY);
         cp = QPoint(leftX, bottomY);
          bp.quadTo(leftX, bottomY, leftX, bottomY + CORNER_RADIUS);

                  // arrow
         if (leftArrow) {
              bp.lineTo(leftX, topY-ARROW_HEIGHT-ARROW_TOP);
              bp.lineTo(leftOX, topY-ARROW_HEIGHT/2-ARROW_TOP);
              bp.lineTo(leftX, topY-ARROW_TOP);
         }
         // top left corner
         bp.lineTo(leftX, topY - CORNER_RADIUS);
         bp.quadTo(leftX, topY, startingPoint.x(), startingPoint.y());
         bp.closeSubpath();
 }

void ChatItemDelegate::drawRect(QPainter* const painter, QRect const& rect, bool const isSelected, bool const isActivated, bool const leftArrow) const
{
  //       NSBezierPath *bp = [self bezierPathWithRect:rect];
    QPainterPath pp;
    bezierPathWithRect(rect, pp, leftArrow);
    QGraphicsPathItem bp(pp);
    QGraphicsDropShadowEffect theShadow;

    QPen pen;
    pen.setJoinStyle(Qt::RoundJoin);
    pen.setStyle(Qt::SolidLine);
     if (isSelected){
         pen.setWidth(2);
         if (isActivated)
         {

             pen.setColor(QColor(50,120, 200));
         }
         else
         {
             pen.setColor(QColor(50,50,50));
         }

     }
     else {

         theShadow.setOffset(1.0, 1.0);
         theShadow.setBlurRadius(4.0);
         theShadow.setColor(QColor(0,0,0, 255.0*0.3));

         pen.setColor(QColor(255.0*0.69, 255.0*0.77, 255.0*0.7));
         pen.setWidth(1.0);
         bp.setGraphicsEffect(&theShadow);
     }
     painter->setPen(pen);
     painter->setRenderHint(QPainter::Antialiasing);

     QColor startingColor;
     QColor endingColor;
     if (leftArrow) {
         startingColor = QColor(200,208,230);
         endingColor = QColor(180,180,210);
     }
     else {
         startingColor = QColor(200,227,230);
         endingColor = QColor(180,190,210);
     }

     pp.setFillRule(Qt::WindingFill);
     QLinearGradient gradient;
     gradient.setColorAt(0, startingColor);
     gradient.setColorAt(1, endingColor);
     gradient.setStart(rect.bottomLeft());
     gradient.setFinalStop(rect.topLeft());
     painter->setBrush(gradient);
     painter->drawPath(pp);

     //NSGradient *grd = [[NSGradient alloc] initWithStartingColor:startingColor
     //[grd drawInBezierPath:bp angle:-90];
     //[grd release];
 }

void ChatItemDelegate::MakeHtmlString(const QModelIndex & index, QString& html) const
{
    html = QString("%1<br><font size=1 color='gray'>%2</font>")
           .arg(index.data().value<QString>())
           .arg(index.data(TIMESTAMP_ROLE).value<QString>());
    html.replace("\n", "<br>");
}


void ChatItemDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
    bool bLeftArrow;
    bLeftArrow = index.data(ARROW_ROLE).value<bool>();

    switch(index.column())
    {
    case 0:
        if (bLeftArrow && contactProfileImage)
        {
            painter->save();

            painter->drawPixmap(option.rect.x()+2,
                                option.rect.y()-2+option.rect.height()-contactProfileImage->size().height(),
                                contactProfileImage->size().width(),
                                contactProfileImage->size().height(),
                                *contactProfileImage);

            painter->restore();

        }
        //QStyledItemDelegate::paint(painter, option, index);
        break;

    case 1:
        {
            QString html;
            MakeHtmlString(index, html);
            document->clear();

            document->setTextWidth(option.rect.width()-ARROW_WIDTH-4 - PROFILE_AREA_WIDTH);
            document->setHtml(html);
            //document->adjustSize();
            QSize textSize = document->size().toSize();
            if (document->idealWidth() < textSize.width())
            {
                textSize.setWidth(document->idealWidth());
            }
            textSize += QSize(4+ARROW_WIDTH,4);

            painter->save();
            painter->fillRect(option.rect, QColor(255,255,255));

            QRect textRect = option.rect;
            textRect.setSize(textSize);

            if (!bLeftArrow)
            {
                textRect.moveLeft(textRect.x() + option.rect.right() - textRect.right() - PROFILE_AREA_WIDTH);
            }


            drawRect(painter, textRect, option.state&QStyle::State_Selected?true:false,
                     option.state&QStyle::State_Active?true:false, bLeftArrow);
            painter->restore();


            painter->save();
            painter->translate(textRect.x()+2+(bLeftArrow?ARROW_WIDTH:0), textRect.y()+2);
            document->drawContents(painter);
             painter->restore();
        }
        break;
    default:
        break;

    }
}

QSize ChatItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{

    switch(index.column())
    {
    case 0:
    case 2:
        return QSize(PROFILE_AREA_WIDTH,50);
        break;
    case 1:
        {
            QString html;
            MakeHtmlString(index, html);

            QRect rect = option.rect;
            document->clear();
            document->setTextWidth(rect.width()-4-ARROW_WIDTH - PROFILE_AREA_WIDTH);
            document->setHtml(html);
            QSize requiredSize = document->size().toSize();
            requiredSize += QSize(4+ARROW_WIDTH, 4);
            return QSize(-1, requiredSize.height());

        }
        break;
    default:
        break;

    }

    return QSize(PROFILE_AREA_WIDTH,50);
}

ChatTableModel::ChatTableModel(MessageList& list, QObject *parent) :
    QAbstractTableModel(parent),
    messageList(list)
{
}

int ChatTableModel::rowCount(const QModelIndex &parent) const
 {
     Q_UNUSED(parent);
     return messageList.size();
 }

 int ChatTableModel::columnCount(const QModelIndex &parent) const
 {
     Q_UNUSED(parent);
     return 2;
 }


 QVariant ChatTableModel::data(const QModelIndex &index, int role) const
  {
      if (!index.isValid())
          return QVariant();

      if (index.row() >= messageList.size() || index.row() < 0)
          return QVariant();

      switch (role)
      {
      case Qt::DisplayRole:
      {
          if (index.column() == 0)
              return QVariant();
          else if (index.column() == 1)
          {
              return messageList[index.row()].getMessage();
          }
      }
          break;
      case TIMESTAMP_ROLE:
          {
              return messageList[index.row()].getDateTime();
          }

      case ARROW_ROLE:
          {
              return messageList[index.row()].getLeftArrow();
          }
      case Qt::DecorationRole:
              if (index.column() == 0)
              {

                  //return Q
              }
          break;
      case Qt::BackgroundRole:
          {
//              QRect rect(0,0,nWidth,30);

  //           return drawRect(rect, false, false,false);
          }
//          return index.row()%2?QBrush(QColor(255,255,255)):QBrush(QColor(237,243,255));
          break;
      case Qt::SizeHintRole:
          //if (index.column() == 0)
          //     return QSize(42,100);
          break;

      }
      return QVariant();
  }

 void ChatTableModel::addMessage(MessageItem& item)
 {

     beginInsertRows(QModelIndex() ,messageList.size(), messageList.size());
     messageList.append(item);
     endInsertRows();
 }
